package com.cloud.minioService.utils;

import io.minio.*;
import io.minio.messages.Item;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * @author zhozixiong
 * @date 2023/03/02
 *
 * minio工具类
 */
public class MinioUtil {

    private String endpoint;
    private String accessKey;
    private String secretKey;

    private MinioClient minioClient;

    private final String FOLDER_SEPARATOR = "/";
    private final String FILE_SEPARATOR = ".";
    private final String TOP_FOLDER = "/upload/";
    private final int FILENAME_MAXSIZE = 32;

    public MinioUtil(String endpoint, String accessKey, String secretKey) {
        this.endpoint = endpoint;
        this.accessKey = accessKey;
        this.secretKey = secretKey;
        createMinioClient();
    }

    /**
     * 初始化MinioClient
     */
    public void createMinioClient() {
        try {
            if(minioClient == null) {
                minioClient = MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();
            }
        }catch (Exception e) {
            System.err.println("连接Minio服务器异常:" + e);
        }
    }

    //操作桶

    /**
     * 创建容器
     * @param bucketName bucket名称
     */
    public void createBucket(String bucketName) throws Exception {
        //先验证容器是否存在,不存在再创建
        if(!existBucket(bucketName)) {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
    }

    /**
     * 验证bucket是否存在
     * @param bucketName bucket名称
     * @return true:存在
     */
    public boolean existBucket(String bucketName) throws Exception {
        return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
    }

    /**
     * 删除bucket
     * @param bucketName bucket名称
     */
    public void removeBucket(String bucketName) throws Exception {
        minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
    }

    //操作文件

    /**
     * 生成文件名
     * @param file 文件
     * @param isRetain 是否保留源文件名
     * @return 返回文件名
     */
    private String getFilePathName(MultipartFile file, boolean isRetain) {
        String fileName = file.getOriginalFilename();
        //文件原来名称
        String name = fileName;
        //文件后缀
        String prefix = "";
        if(fileName.indexOf(FILE_SEPARATOR) != -1) {
            name = fileName.substring(0, fileName.indexOf(FILE_SEPARATOR));
            prefix = fileName.substring(fileName.lastIndexOf(FILE_SEPARATOR));
        }
        LocalDate date = LocalDate.now();
        StringBuilder filePathName = new StringBuilder(TOP_FOLDER);
        filePathName.append(date.getYear());
        filePathName.append(FOLDER_SEPARATOR);
        filePathName.append(date.getMonthValue());
        filePathName.append(FOLDER_SEPARATOR);
        filePathName.append(date.getDayOfMonth());
        filePathName.append(FOLDER_SEPARATOR);
        //生成随机后缀
        Random r = new Random();
        int pix=r.ints(1, (100 + 1)).findFirst().getAsInt();
        //将时间戳作为主文件名
        filePathName.append(System.currentTimeMillis());
        //添加随机后缀;同一时间生成多个名字就可能导致重名,所以要添加随机后缀
        filePathName.append(pix);
        //判断是否要保存原文件名
        if(isRetain) {
            //添加分割符
            filePathName.append("_");
            //文件名超过32字符则截取
            if(name.length() >= FILENAME_MAXSIZE) {
                name = name.substring(0,32);
            }
            filePathName.append(name);
        }
        filePathName.append(prefix);
        return filePathName.toString();
    }

    /**
     * 上传文件
     */
    public List<String> uploadFiles(String bucketName, MultipartFile... files) {
        return uploadFiles(false, bucketName, files);
    }

    public List<String> uploadFiles(boolean isRetain, String bucketName, MultipartFile... files) {
        if(files.length < 1) {
            throw new RuntimeException("上传文件为空!");
        }
        List<String> nameList = new ArrayList<>();
        for(MultipartFile file : files) {
            nameList.add(uploadFile(isRetain, bucketName, file));
        }
        return nameList;
    }

    private String uploadFile(boolean isRetain, String bucketName, MultipartFile file) {
        String fileName = getFilePathName(file, isRetain);
        try {
            //在创建之前有判断bucket是否存在
            createBucket(bucketName);
            InputStream inputStream = file.getInputStream();
            minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(fileName).contentType(file.getContentType()).stream(inputStream, inputStream.available(), -1).build());
            return fileName;
        }catch (Exception e) {
            throw new RuntimeException("上传失败");
        }
    }

    /**
     * 下载文件
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @return 数据流
     */
    public InputStream getObject(String bucketName, String objectName) throws Exception {
        return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
    }

    /**
     * 判断文件是否存在
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @return 文件是否存在
     */
    public boolean doesObjectExist(String bucketName, String objectName) {
        boolean exist = true;
        try {
            minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
        }catch (Exception e) {
            exist = false;
        }
        return exist;
    }

    /**
     * 判断文件夹是否存在
     * @param bucketName bucket名称
     * @param objectName 文件夹名称
     * @return true:存在
     */
    public boolean doesFolderExist(String bucketName, String objectName) {
        boolean exist = false;
        try {
            Iterable<Result<Item>> resultIterable = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(objectName).recursive(false).build());
            for (Result<Item> result : resultIterable) {
                Item item = result.get();
                if(item.isDir() && objectName.equals(item.objectName())) {
                    exist = true;
                    break;
                }
            }
        }catch (Exception e) {
            exist = false;
        }
        return exist;
    }

    /**
     * 删除文件
     * @param bucketName bucket名称
     * @param objectName 文件名称
     */
    public void removeObject(String bucketName, String objectName) throws Exception {
        minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
    }
}
